/**
 * Created with CLion.
 * Description:
 * User: loong
 * Date: 2024/8/30
 * Time: 17:01
 */

#include "Server.h"

#include <filesystem>

Server::Server()
    : context_(1)
    , snapshot_(context_, zmq::socket_type::router)
    , publisher_(context_, zmq::socket_type::pub)
    , collector_(context_, zmq::socket_type::pull)
{
    snapshot_.bind("tcp://*:11556");
    publisher_.bind("tcp://*:11557");
    collector_.bind("tcp://*:11558");
}

void Server::Run()
{
    while(true) {
        zmq::pollitem_t items[] = {
                {static_cast<void *>(collector_), 0, ZMQ_POLLIN, 0},
                {static_cast<void *>(snapshot_), 0, ZMQ_POLLIN, 0}};

        zmq::poll(items, 2, 1000);

        //collector_  信息收集
        if(items[0].revents & ZMQ_POLLIN) {
            zmq::message_t message;
            collector_.recv(message, zmq::recv_flags::none);

            Chat::Internal::SingleMessage msg;

            bool ret = msg.ParseFromArray(message.data(), message.size());
            assert(ret);

            std::lock_guard<std::mutex> lock(mutex_);
            msg.set_sequence(sequence_++);

            std::cout << "receive " << msg.clientid() << " message:" << msg.sequence() << " " << msg.content() << std::endl;

            all_messages_[msg.sequence()] = std::move(msg);
            std::cout << "message size: " << all_messages_.size() << std::endl;

            //将某客户端的信息作为主题信息发布
            publisher_.send(message, zmq::send_flags::none);
        }
        //snapshot_ 快照请求回复(仅上线时的快照请求)
        if(items[1].revents & ZMQ_POLLIN) {
            // [1]上线消息接收
            zmq::message_t identity_msg;
            snapshot_.recv(identity_msg, zmq::recv_flags::none);

            zmq::message_t last_message;
            snapshot_.recv(last_message, zmq::recv_flags::none);

            Chat::Internal::LogInMessage received_msg;
            received_msg.ParseFromString(last_message.to_string());

            // [2]回复请求
            // [2.1] 去除指定ID前的无用消息
            Chat::Internal::CombMessage comb_msg;
            for(const auto & [seq, message] : all_messages_) {
                if(seq <= received_msg.lastid())
                    continue;

                comb_msg.add_messages()->CopyFrom(message);
            }
            // [2.2] 发送快照
            std::string serialized_message;

            bool ret = comb_msg.SerializeToString(&serialized_message);
            assert(ret);

            // router转发需增加id
            snapshot_.send(identity_msg, zmq::send_flags::sndmore);
            snapshot_.send(zmq::message_t(serialized_message), zmq::send_flags::none);
        }
    }
}
